package com.leenmvc.core.aop.proxy;

import com.leenmvc.core.dao.communal.BaseDao;
import com.leenmvc.core.utils.thread.ThreadLocalManager;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 代理BaseDao所有方法，并根据不同的注解进行不同的AOP操作
 */
public class ProxyBaseDao implements InvocationHandler {

    private BaseDao before;

    private BaseDao after;

    Object object;

    public ProxyBaseDao(Object object, BaseDao before, BaseDao after) {
        this.object = object;
        this.before = before;
        this.after = after;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        try {
            beforeOperation(method, args);
            ThreadLocalManager.put("startTime", System.currentTimeMillis());
            result = method.invoke(object, args);
            ThreadLocalManager.put("excuteTime", (int)(System.currentTimeMillis() - (Long)ThreadLocalManager.get("startTime")));
            afterOperation(method, args);
        } catch (NoSuchMethodException e) {
            throw e.getCause();
        } catch (InvocationTargetException e) {
            throw e.getCause();
        } catch (IllegalAccessException e) {
            throw e.getCause();
        }
        return result;
    }

    /**
     * 调用实现同一接口的方法前验证
     *
     * @param method
     * @param args
     */
    private <T> void beforeOperation(Method method, Object[] args) throws Throwable {
        Class<?> beforeCls = before.getClass();
        String methodName = method.getName();
        Method beforeMethod = null;
        try {
            beforeMethod = beforeCls.getMethod(methodName, method.getParameterTypes());
            beforeMethod.invoke(before, args);
        } catch (IllegalAccessException e) {
            throw e.getCause();
        } catch (InvocationTargetException e) {
            throw e.getCause();
        } catch (NoSuchMethodException e) {
            throw e.getCause();
        }
    }

    /**
     * 调用实现同一接口的方法前验证
     *
     * @param method
     * @param args
     */
    private <T> void afterOperation(Method method, Object[] args) throws Throwable {
        Class<?> afterCls = after.getClass();
        String methodName = method.getName();
        Method beforeMethod = null;
        try {
            beforeMethod = afterCls.getMethod(methodName, method.getParameterTypes());
            beforeMethod.invoke(after, args);
        } catch (IllegalAccessException e) {
            throw e.getCause();
        } catch (InvocationTargetException e) {
            throw e.getCause();
        } catch (NoSuchMethodException e) {
            throw e.getCause();
        }

    }

    public Object getObject() {
        return object;
    }

    public void setObject(Object object) {
        this.object = object;
    }
}
